/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "msdp_angle_algorithm.h"

#include <thread>
#include "spatial_awareness_common.h"
#include "constants.h"

namespace OHOS {
namespace Msdp {
bool MsdpAngleAlgorithm::Enable(std::shared_ptr<SpatialCallback> &callback)
{
    SPATIAL_LOGI(MODULE_SERVICE, "%{public}s Init enable", __func__);

    if (rdbMgr_ == nullptr) {
        rdbMgr_ = std::make_unique<SpatialRdbManager>();
    }

    SpatialRdbManager::SpatialEventCallback eventCallback =
        std::bind(&MsdpAngleAlgorithm::ReceiveAngleEventData, this, std::placeholders::_1);
    rdbMgr_->RegisterEventCallback(SpatialRdbManager::CMD_ANGLE, eventCallback);

    callback_ = callback;

    bool ret = rdbMgr_->Init(SpatialRdbManager::CMD_ANGLE);
    if (!ret) {
        SPATIAL_LOGE(MODULE_ALGORITHM, "rdb manager init fail");
        return ret;
    }
    return true;
}

bool MsdpAngleAlgorithm::Disable()
{
    callback_->OnEnd();
    return true;
}

bool MsdpAngleAlgorithm::ReceiveAngleEventData(const SpatialEvent &event)
{
    SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s enter", __func__);
    updateEvent_ = event;
    SPATIAL_LOGI(MODULE_SERVICE,
        "%{public}s OnResult direction: %{public}d, distance: %{public}f, angle: %{public}f"
        "exist: %{public}d, innerouter: %{public}d", __func__, updateEvent_.direction,
        updateEvent_.distance, updateEvent_.angle, updateEvent_.exist, updateEvent_.innerOuter);
    return true;
}

void MsdpAngleAlgorithm::HandleSpecialRes(SpatialDevice center, SpatialDevice peer)
{
    SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s enter", __func__);
    if ((center.typeId == TYPE_CAR && peer.typeId == TYPE_PHONE) ||
        (center.typeId == TYPE_PHONE && peer.typeId == TYPE_CAR)) {
        SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s update special device", __func__);
        updateEvent_.direction = SpatialDirection::INVALID;
        updateEvent_.distance = INVALID_DATA;
        updateEvent_.angle = INVALID_DATA;
        updateEvent_.exist = static_cast<bool>(EXIST_MIN_VALUE);
        updateEvent_.mode = INVALID_MODE | INNEROUTER_MODE;
    }
}

bool MsdpAngleAlgorithm::Trigger(SpatialDevice center, std::vector<SpatialDevice> around)
{
    SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s enter", __func__);
    if (around.empty()) {
        SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s peer device list is empty", __func__);
        return false;
    }
    for (auto peer = around.begin(); peer != around.end(); peer++) {
        SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s callback angle result", __func__);
        HandleSpecialRes(center, *peer);
        if (center.deviceId == peer->deviceId && center.typeId == peer->typeId &&
            center.deviceName == peer->deviceName) {
                return false;
        }

        if (updateEvent_.device.deviceId == peer->deviceId && updateEvent_.device.typeId == peer->typeId &&
            updateEvent_.device.deviceName == peer->deviceName) {
            callback_->OnResult(updateEvent_);
        } else {
            SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s callback new device", __func__);
            updateEvent_.device.deviceId = peer->deviceId;
            updateEvent_.device.deviceName = peer->deviceName;
            updateEvent_.device.typeId = peer->typeId;
            callback_->OnResult(updateEvent_);
        }
    }
    return true;
}

MsdpAlgorithmCapability MsdpAngleAlgorithm::GetCapability()
{
    MsdpAlgorithmCapability capability;
    capability.type = AlgorithmType::ANGLE;
    capability.version = "1.0.0";
    capability.vecdor = "com.vector";
    capability.description = "AngleAlgorithm";
    capability.mediumMap_.insert(std::make_pair(TransmissionMedium::WIFI, MediumPriority::HIGH));
    capability.mediumMap_.insert(std::make_pair(TransmissionMedium::ETHERNET, MediumPriority::MIDDLE));
    return capability;
}

extern "C" MsdpAlgorithmInterface *Create(void)
{
    SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s enter", __func__);
    return new MsdpAngleAlgorithm();
}

extern "C" void Destroy(MsdpAlgorithmInterface *algorithm)
{
    SPATIAL_LOGI(MODULE_ALGORITHM, "%{public}s enter", __func__);
    delete algorithm;
}
} // namespace Msdp
} // namespace OHOS